package com.vrv.mysqlback;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * @ClassName: MysqldumpExecutor
 * @Desc: TODO
 * @Auther: <Bang>
 * @Date: 2021/08/27 11:14
 * @Version: 1.0
 * @Modified By:
 */
public class MysqldumpExecutor {

    private static final Logger log = LoggerFactory.getLogger(MysqldumpExecutor.class);
    /**
     * The path of the mysqldump executable.
     */
    private String mysqldumpExecutablePath;

    /**
     * Arguments for the executable.
     */
    private ArrayList args = new ArrayList();

    /**
     * The process representing the mysqldump execution.
     */
    private Process mysqldump = null;

    /**
     * A process killer to kill the mysqldump process with a shutdown hook, useful
     * if the jvm execution is shutted down during an ongoing encoding process.
     */
    private ProcessKiller mysqldumpKiller = null;

    /**
     * A stream reading from the mysqldump process standard output channel.
     */
    private InputStream inputStream = null;

    /**
     * A stream writing in the mysqldump process standard input channel.
     */
    private OutputStream outputStream = null;

    /**
     * A stream reading from the mysqldump process standard error channel.
     */
    private InputStream errorStream = null;

    private String command;

    public String getCommand() {
        return command;
    }

    public void setCommand(String command) {
        this.command = command;
    }

    /**
     * It build the executor.
     *
     * @param mysqldumpExecutablePath The path of the mysqldump executable.
     */
    public MysqldumpExecutor(String mysqldumpExecutablePath) {
        this.mysqldumpExecutablePath = mysqldumpExecutablePath;
    }

    /**
     * Adds an argument to the mysqldump executable call.
     *
     * @param arg The argument.
     */
    public void addArgument(String arg) {
        args.add(arg);
    }

    public void addDefaultArgs(String... arg){
        for (String s : arg) {
            args.add(s);
        }
    }

    /**
     * Executes the mysqldump process with the previous given arguments.
     *
     * @throws IOException If the process call fails.
     */
    public void execute() throws IOException {
        int argsSize = args.size();
        String[] cmd = null;
        if (OperatingSystemUtils.isWindows()) {
            // Runtime.getRuntime().exec() 还有一些局限性, 就是无法像cmd那样执行较为复杂的命令. 比如, 输出流的重定向
            cmd = new String[argsSize + 3];
            cmd[0] = "cmd.exe";
            cmd[1] = "/C";
            cmd[2] = mysqldumpExecutablePath;
            for (int i = 0; i < argsSize; i++) {
                cmd[i + 3] = (String) args.get(i);
            }
        } else {
            cmd = new String[argsSize + 1];
            cmd[0] = mysqldumpExecutablePath;
            for (int i = 0; i < argsSize; i++) {
                cmd[i + 1] = (String) args.get(i);
            }
        }

        Runtime runtime = Runtime.getRuntime();
        log.info("exec cmd: {}", Arrays.toString(cmd));
        this.command = ProcessCommandUtils.buildCommand(cmd);
        log.info("exec cmd: {}", Arrays.toString(cmd));
        mysqldump = runtime.exec(cmd);
        mysqldumpKiller = new ProcessKiller(mysqldump);
        runtime.addShutdownHook(mysqldumpKiller);
        inputStream = mysqldump.getInputStream();
        outputStream = mysqldump.getOutputStream();
        errorStream = mysqldump.getErrorStream();
    }

    /**
     * Returns a stream reading from the mysqldump process standard output channel.
     *
     * @return A stream reading from the mysqldump process standard output channel.
     */
    public InputStream getInputStream() {
        return inputStream;
    }

    /**
     * Returns a stream writing in the mysqldump process standard input channel.
     *
     * @return A stream writing in the mysqldump process standard input channel.
     */
    public OutputStream getOutputStream() {
        return outputStream;
    }

    /**
     * Returns a stream reading from the mysqldump process standard error channel.
     *
     * @return A stream reading from the mysqldump process standard error channel.
     */
    public InputStream getErrorStream() {
        return errorStream;
    }

    /**
     * If there's a mysqldump execution in progress, it kills it.
     */
    public void destroy() {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (Throwable t) {
                ;
            }
            inputStream = null;
        }
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (Throwable t) {
                ;
            }
            outputStream = null;
        }
        if (errorStream != null) {
            try {
                errorStream.close();
            } catch (Throwable t) {
                ;
            }
            errorStream = null;
        }
        if (mysqldump != null) {
            mysqldump.destroy();
            mysqldump = null;
        }
        if (mysqldumpKiller != null) {
            Runtime runtime = Runtime.getRuntime();
            runtime.removeShutdownHook(mysqldumpKiller);
            mysqldumpKiller = null;
        }
    }

}
